from dataclasses import dataclass
import json
from typing import List, Literal
from dataclasses_json import dataclass_json
import os
import queue
import threading
import time
import webbrowser
import sys
import pystray
from pystray import Menu, MenuItem
from PIL import Image
from flask import Flask, request, send_from_directory, redirect, jsonify
import win32com.client as win32
import pythoncom
from SkyOfficeLint.info_extractors import extract_doc_full_info
from SkyOfficeLint.info_extractors.extractors import context


abs_path = lambda f: os.path.abspath(os.path.join(os.path.dirname(__file__), f))

app = Flask(__name__, static_folder=abs_path("./static"))
UPLOAD_FOLDER = ".officelint"
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

logs_lock = threading.Lock()

LOG_TYPES = Literal["error", "info", "warning", "violation"]


@dataclass_json
@dataclass
class Log:
    type: LOG_TYPES
    content: str


@dataclass_json
@dataclass
class AppStatus:
    latest_loglines: List[Log]
    busy: bool = False
    currentFile: str = ""

    # violations: List[str]  # 扫描出的违规现象
    # latest_violations:

    def add_violation():
        pass

    def log(
        self,
        type: LOG_TYPES,
        log: str,
    ):
        self.latest_loglines.append(Log(type, log))

    def clear_log(self):
        logs_lock.acquire()
        self.latest_loglines = []
        logs_lock.release()

    # def to_dict(self):
    #     return {"busy": self.busy, "latest_loglines": self.latest_loglines}


app_status = AppStatus([])
tasksQueue = queue.Queue(1)


@app.route("/")
def index():
    return redirect("/index.html")


@app.route("/<path:filename>")
def serve_static(filename):
    return send_from_directory(app.static_folder, filename)


@app.route("/status")
def status():
    val = jsonify(app_status.to_dict())
    app_status.clear_log()
    return val


def allowed_file(filename: str):
    return "." in filename and filename.rsplit(".", 1)[1].lower() in {"doc", "docx"}


@app.route("/upload", methods=["POST"])
def upload_file():
    if app_status.busy:
        return "目前正忙，请等待当前分析完成", 400
    if "file" not in request.files:
        return "没有文件", 400
    file = request.files["file"]
    if file.filename == "":
        return "没有选择文件", 400
    if file and allowed_file(file.filename):
        filename = os.path.join(UPLOAD_FOLDER, file.filename)
        file.save(filename)

        tasksQueue.put(filename)
        app_status.currentFile = filename
        print("上传成功")

        return "文件上传成功", 200
    else:
        return "不允许的文件类型", 400


def handle_task():
    while 1:
        # try:
        app_status.busy = False
        filename = tasksQueue.get()
        app_status.log("info", "收到任务，开始处理！")
        app_status.busy = True

        pythoncom.CoInitialize()

        word_app = win32.gencache.EnsureDispatch("Word.Application")
        word_app.Visible = False
        app_status.log("info", "已后台打开Microsoft Word")
        doc = word_app.Documents.Open(os.path.abspath(filename))
        app_status.log("info", f"已打开文件 {os.path.basename(filename)}")
        app_status.log("info", f"正在提取文档信息 ...")
        context.status = app_status
        documentInfo = extract_doc_full_info(doc)
        app_status.log("info", f"文档信息提取完成，开始检测...")
        print(
            documentInfo.to_json(indent=2, ensure_ascii=False),
        )
        # documentInfo.iter_paragraphs()
        doc.Close()
        word_app.Quit()


should_exit = False


def quit_window(icon: pystray.Icon):
    global should_exit
    icon.stop()
    should_exit = True


def show_window():
    webbrowser.open("http://localhost:5000")


menu = (
    MenuItem("显示扫描网页", show_window, default=True),
    # Menu.SEPARATOR,
    MenuItem("退出程序", quit_window),
)
image = Image.open(abs_path("static/icon.png"))
icon = pystray.Icon("icon", image, "图标名称", menu)


def main():
    # if __name__ == "__main__":
    threading.Thread(target=icon.run, daemon=True).start()
    threading.Thread(target=app.run, daemon=True).start()
    threading.Thread(target=handle_task, daemon=True).start()
    while 1:
        time.sleep(0.5)
        # handle_task()
        if should_exit:
            sys.exit(0)
